package me.zhengjie.tool;


import me.zhengjie.vo.Constant;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 期号yyyyMM
 *
 * @author tianqi
 */
public class Ym implements Serializable {

    private static final long serialVersionUID = 6272780232965952105L;
    private Integer yearMonth;

    private static final String ZEROERROR = "期号为0，不能计算";

    /**
     * 构造期号
     *
     * @param yyyyMM 年月，例如"201805"； 或者年度如“2018”
     */
    public Ym(String yyyyMM) {
        if (!ValidateUtil.isEmpty(yyyyMM)) {
            this.yearMonth = Integer.valueOf(yyyyMM);
            valid(this.yearMonth);
        }
    }

    /**
     * @param yyyyMM 年月，例如"201805"； 或者年度如“2018”
     */
    public Ym(Integer yyyyMM) {
        if (!ValidateUtil.isEmpty(yyyyMM)) {
            this.yearMonth = yyyyMM;
            valid(this.yearMonth);
        }
    }

    /**
     * 获取int类型期号
     *
     * @return
     */
    public Integer intValue() {
        if (!ValidateUtil.isEmpty(this.yearMonth)) {
            return this.yearMonth.intValue();
        }
        return null;
    }

    /**
     * 日期转换成期号
     *
     * @param date
     */
    public static Ym getYmByDate(Date date) {
        return new Ym(DateUtil.date2Str(date, Constant.DEFAULT_FORMAT_YM));
    }

    /**
     * 期号增减
     *
     * @param ym  yyyyMM期号
     * @param cnt 增加减少月数
     * @return
     */
    public static Integer addMonths(Integer ym, Integer cnt) {
        valid(ym);
        if (ValidateUtil.isEmpty(cnt)) {
            throw new IllegalArgumentException("增加月数=null");
        }
        if (0 == ym.intValue()) {
            throw new IllegalArgumentException(ZEROERROR);
        }
        Integer year = ym / 100;
        Integer months = ym % 100;
        if (cnt / 12 != 0) {
            year += cnt / 12;
        }
        if (months + cnt % 12 > 12) {
            year += 1;
            months = months + cnt % 12 - 12;
        } else if (months + cnt % 12 <= 0) {
            year -= 1;
            months = months + cnt % 12 + 12;
        } else {
            months += cnt % 12;
        }
        return year * 100 + months;
    }

    /**
     * 期号增减
     *
     * @param months 期号增减月数
     * @return 返回一个新的增减变动后的期号
     */
    public Ym addMonths(Integer months) {
        NPETool.isEmptyThrowException(months, "期号增减月数");
        if (0 == this.yearMonth.intValue()) {
            throw new IllegalArgumentException(ZEROERROR);
        }
        return new Ym(addMonths(this.yearMonth, months));
    }

    /**
     * 获得上一期
     *
     * @return
     */
    public Ym getLastYm() {
        return new Ym(addMonths(this.yearMonth, -1));
    }

    public static Integer getLastYm(Integer months) {
        return addMonths(months, -1);
    }

    public static Integer getLastYm(String months) {
        return addMonths(new Integer(months), -1);
    }

    /**
     * 获得下一期
     *
     * @return
     */
    public Ym getNextYm() {
        return new Ym(addMonths(this.yearMonth, 1));
    }

    public static Integer getNextYm(Integer months) {
        return addMonths(months, 1);
    }

    public static Integer getNextYm(String months) {
        return addMonths(new Integer(months), 1);
    }

    public static Ym getNextYm(Ym ym) {
        return new Ym(addMonths(ym.intValue(), 1));
    }

    /**
     * 计算两个期号之间的月数
     *
     * @param ym1
     * @param ym2
     * @return
     */
    public static int monthsBetween(Integer ym1, Integer ym2) {
        if (0 == ym1.intValue() || 0 == ym2.intValue()) {
            throw new IllegalArgumentException(ZEROERROR);
        }
        int k = ym1;
        ym1 = k >= ym2 ? k : ym2;
        ym2 = k < ym2 ? k : ym2;
        int yearnum = ym1 / 100 - ym2 / 100;
        int monthnum = ym1 % 100 - ym2 % 100;
        if (monthnum < 0) {
            return 12 * (yearnum - 1) + (12 + monthnum);
        } else if (monthnum > 0) {
            return 12 * yearnum + monthnum;
        } else {
            return 12 * yearnum;
        }
    }

    public static int monthsBetween(Ym ym1, Ym ym2) {
        return monthsBetween(ym1.intValue(), ym2.intValue());
    }

    /**
     * 计算当前期号与结束期号之间月数
     *
     * @param endYm 结束期号
     * @return 返回当前期号与结束期号之间月数
     */
    public Integer monthsBetween(Ym endYm) {
        NPETool.isEmptyThrowException(endYm, "结束期号");
        if (0 == this.yearMonth.intValue() || 0 == endYm.intValue()) {
            throw new IllegalArgumentException(ZEROERROR);
        }
        return monthsBetween(this.yearMonth, endYm.toInteger());
    }

    public Integer toInteger() {
        if (ValidateUtil.isEmpty(this.yearMonth)) {
            return null;
        } else {
            return this.yearMonth;
        }
    }

    public String toString() {
        if (ValidateUtil.isEmpty(this.yearMonth)) {
            return "";
        } else {
            return this.yearMonth.toString();
        }
    }

    /**
     * 验证期号有效性
     *
     * @param ym 期号
     */
    public static void valid(Integer ym) {
        if (ValidateUtil.isEmpty(ym)) {
            throw new IllegalArgumentException("期号=null");
        } else {
            if (0 == ym.intValue()) {
                return;
            }
            if (ym.toString().length() >= 6) { //如果是年度就不用判断，是期号才判断
                if (190001 >= ym) {
                    throw new IllegalArgumentException("不允许期号(" + ym + ")小于190001");
                }
                if (999912 < ym) {
                    throw new IllegalArgumentException("不允许期号(" + ym + ")大于999912");
                }
                Integer month = new Integer(String.valueOf(ym).substring(4));
                if (1 > month.intValue() || 12 < month.intValue()) {
                    throw new IllegalArgumentException("期号(" + ym + ")月份不正确");
                }
            }
        }
    }

    /**
     * 获取两个期号之间的月份
     *
     * @param issue1
     * @param issue2
     * @return
     */
    public static int[] ymMonth(int issue1, int issue2) {
        int k = issue1;
        issue1 = k >= issue2 ? k : issue2;
        issue2 = k < issue2 ? k : issue2;
        int months = monthsBetween(issue1, issue2);
        int[] intArray = new int[months + 1];
        intArray[0] = issue2;
        intArray[months] = issue1;
        int year = issue2 / 100;
        int month = issue2 % 100;
        for (int i = 1; i < months; i++) {
            month++;
            if (month > 12) {
                year++;
                month = 1;
            }
            intArray[i] = Integer.valueOf("" + year + (month < 10 ? "0" + month : month));
        }
        return intArray;
    }

    /**
     * @Description 获取应用服务器时间的当前年月
     * @Author
     * @Return int
     * @Exception
     * @CreateDate 2018/5/17 16:47
     */
    public static Ym getCurrentYm() {
        return new Ym(DateUtil.getCurrentTime(Constant.DEFAULT_FORMAT_YM));
    }

    public static Integer getCurrentYmInteger() {
        return new Ym(DateUtil.getCurrentTime(Constant.DEFAULT_FORMAT_YM)).intValue();
    }

    public static String getCurrentYmString() {
        return new Ym(DateUtil.getCurrentTime(Constant.DEFAULT_FORMAT_YM)).toString();
    }

    /**
     * @return {@link Integer }
     * @Description 得到当前年度整数
     * @Author jzy
     * @Date 2021/12/14
     */
    public static Integer getCurrentYearInteger() {
        return new Ym(DateUtil.getCurrentTime(Constant.DEFAULT_FORMAT_YD)).intValue();
    }

    /**
     * 校验两个时间段是否交叉
     *
     * @param aae041 要校验的开始年月
     * @param aae042 要校验的结束年月
     * @param myMap
     * @return
     */
    public static boolean checkTimeCrossing(Integer aae041, Integer aae042, MyMap myMap) {
        Integer objAae041 = myMap.getAsInteger("aae041");
        Integer objAae042 = myMap.getAsInteger("aae042");
        if (aae041 >= objAae041 && aae041 <= objAae042) {
            return true;
        }
        if (aae042 >= objAae041 && aae042 <= objAae042) {
            return true;
        }
        if (aae041 <= objAae041 && aae042 >= objAae042) {
            return true;
        }
        return false;
    }

    /**
     * 校验两个时间段是否交叉
     *
     * @param aae030 要校验的开始日期
     * @param aae031 要校验的结束日期
     * @param myMap
     * @return
     */
    public static boolean checkDateCrossing(Integer aae030, Integer aae031, MyMap myMap) {
        Integer objAae030 = myMap.getAsInteger("aae030");
        Integer objAae031 = myMap.getAsInteger("aae031");
        if (aae030 >= objAae030 && aae030 <= objAae031) {
            return true;
        }
        if (aae031 >= objAae030 && aae031 <= objAae031) {
            return true;
        }
        if (aae030 <= objAae030 && aae031 >= objAae031) {
            return true;
        }
        return false;
    }

    /**
     * 获取一批期号中连续的区间
     *
     * @param yms
     * @return
     */
    public static List<MyMap> getContinuityYmList(List<Ym> yms) {
        if (ValidateUtil.isEmpty(yms)) {
            return null;
        } else {
            yms.sort(Comparator.comparing((Ym ym) -> ym.intValue()));
            List<MyMap> result = new ArrayList();
            Ym startYm = yms.get(0);
            Ym endYm = null;
            boolean is = false;
            for (int i = 0; i < yms.size(); i++) {
                if (is) {
                    startYm = yms.get(i);
                    is = false;
                }
                Ym parse = yms.get(i);
                Ym parseNext = null;
                if ((i + 1) == yms.size()) {
                    parseNext = yms.get(i);
                } else {
                    parseNext = yms.get(i + 1);
                }

                Ym parse1 = getNextYm(parse);

                //如果往后推一个月不连续
                if (parseNext.intValue().compareTo(parse1.intValue()) != 0 || (i + 1) == yms.size()) {
                    if ((i + 1) == yms.size()) { //如果循环到最后一个
                        endYm = parseNext;
                    } else {
                        endYm = parse;
                    }
                    MyMap myMap = new MyMap();
                    myMap.put("startYm", startYm.intValue());
                    myMap.put("endYm", endYm.intValue());
                    result.add(myMap);
                    startYm = parseNext;
                    is = true;
                }
            }
            return result;
        }
    }


    /**
     * @return {@link Integer }
     * @Description 得到当前日期
     * @Author jzy
     * @Date 2021/12/14
     */
    public static String getCurrentYearAllInteger() {
        Date date=new Date();
        SimpleDateFormat f = new SimpleDateFormat(Constant.DEFAULT_FORMAT_S);
        String returnStr = f.format(date);
        return returnStr;
    }

    /**
     * 传入期号进行 返回 时间段
     *
     * @param ymList List<Ym> input = Arrays.asList(new Ym(202301),new Ym(199503),new Ym(202302),new Ym(199412),
     *               new Ym(199501), new Ym(199502), new Ym(199601),new Ym(199702));
     * @return [199412-199503, 199601, 199702, 202301-202302]
     */
    public static List<String> mergeTimePeriod(List<Ym> ymList) {
        ymList = ymList.stream().distinct().sorted(Comparator.comparing(Ym::intValue)).collect(Collectors.toList());
        List<String> result = new ArrayList<>();
        if (ValidateUtil.isEmpty(ymList)) {
            return result;
        }
        Ym start = ymList.get(0);
        Ym end = start;
        for (int i = 1; i < ymList.size(); i++) {
            Ym current = ymList.get(i);
            if (!Objects.equals(current.intValue(), end.addMonths(1).intValue())) {
                if (Objects.equals(start.intValue(), end.intValue())) {
                    result.add(String.valueOf(start));
                } else {
                    result.add(start.intValue() + "-" + end.intValue());
                }
                start = current;
            }
            end = current;
        }
        if (Objects.equals(start.intValue(), end.intValue())) {
            result.add(String.valueOf(start));
        } else {
            result.add(start + "-" + end);
        }
        return result;
    }


}
